• AccessTimes Add-On (restrict the time that people can access your Mac)
• AccessTimes.p (source for AccessTimes Add-On)
• AccessTimes.rsrc (resources for AccessTimes)
• LastResort Add-On (add-on that completely overrides PowerLock)
Add-Ons: A Brief Explanation
PowerLock incorporates Add-On Technology™ which basically means that PowerLock can be extended through the use of procedures that are stored in a separate file from PowerLock, known as an "Add-On" file.
It is expected that PowerLock functionality will be enhanced via the use of add-ons from both the author and other interested persons.
Examples of where Add-Ons can be applied include:
- additional security features specific to each user
- third party routine for altering the boot blocks
- enhanced security features
- integration with other applications and utilities
- making PowerLock a front end to a network
Add-Ons: How to Use Them
To use a PowerLock Add-On, simply place the file inside the same folder as your PowerLock Prefs file. Under System 7 this is the Preferences folder within the System Folder. Under System 6 it is either the actual System folder or the Preferences folder, if established. To operate, the file MUST be called 'PowerLock Add-Ons'. Once you've done this, the add-on will be active whenever PowerLock is run.
(The add-on file can also be placed in the same directory as PowerLock).
You can keep a variety of Add-On files with different names. To use a particular add-on file with PowerLock, just double-click on it. System 7 users can drop the add-on onto PowerLock. But remember, to use the add-on at system startup, it must be called 'PowerLock Add-Ons' and must be accessible by PowerLock.
Add-Ons: How to tell if they're active
In PowerLock, select the About... button and then click the PowerLock icon at the bottom of the window. (ShortCut: Option click the About button). A small box displaying version numbers should appear. Inside this box you will see 'PowerLock Add-Ons Active' if the add-on is active. You might also see the version number of the add-on. If you hold down the option key whilst clicking Okay, a list of all active add-ons will be dumped to the PowerLock Log file, including version information.
Add-Ons: Examples
All example add-ons include their source code which you should use to help write your own Add-Ons.
Dispatcher is a special add-on described in detail later in this document.
LastResort allows you to eliminate PowerLock by placing this add-on inside the same folder as PowerLock Prefs and renaming it to 'PowerLock Add-Ons' - it may help if you forget your password. When it is active, PowerLock will quit when your click on Okay regardless of the password you have entered. Why am I supplying this when it may help people to defeat PowerLock? Well if I don't supply it, someone else will - the reality is that you must first boot from a floppy disk. If SuperSecurity was active you won't have write access to the hard disk anyway. LastResort only works with licenced copies of PowerLock (though it is certainly not difficult to write something similar).
AccessTimes is an add-on that allows you to restrict what time of the day each person using your Mac has access. When you click the User List button from the Preferences dialog, a dialog box will first popup and prompt you to enter access times. Use 24 hour time and separate the start and finish times with a dash eg. 8-13 means 8:00am to 1:59pm; 0-24 means unrestricted access. (Technical Note: Access Time information is stored within your Prefs file. Also, once userlist names have been entered, they will show up on the AccessTimes dialog)
Add-Ons: Code your Own
Included with PowerLock are two THINK Pascal source files that help you to write your own PowerLock Add-Ons.
addOnIntf.p includes all the interface code to enable your add-on to send
and receive messages to/from PowerLock. Also includes access
to internal PowerLock routines.
AccessTimes.p full source code to the AccessTimes add-on
Add-Ons work by intercepting a range of predefined messages sent at certain times by PowerLock as it is running. The Add-On can then choose to act on those messages and can also instruct PowerLock to ignore certain events. The add-on can take advantage of a range of routines resident within PowerLock itself.
There are two different methods of writing the add-on and the choice is up to you.
1. A multi-function add-on that receives all messages from PowerLock (but does not necessarily have to act on them).
2. A single purpose add-on that acts on a single message from PowerLock. This type of add-on requires the use of the Dispatcher add-on. A number of Method 2 add-ons can be executed in sequence in response to a particular PowerLock message.
Method 1:
Code your add-on using the examples as a basis. The main CASE statement must have all messages that your code acts on - be sure to include an otherwise clause to cover all other messages. Create a resource containing the add-on code. The resource type must be 'adOn', and its ID must be 0 - the name is not important. All attributes of the resource should be clear. Store your resource in a file called 'PowerLock Add-Ons' together with any resources used by your add-on.
Method 2:
Code your specific add-on using any of the examples as the basis. The main CASE statement should include only the message you want to receive, the aReqVersion message plus an OTHERWISE clause. (Please always ensure your add-on handles the aReqVersion message). If you want to create a multipurpose add-on that can be installed for any message, then use the following example:
CASE message of
aReqVersion:
begin
addOn^.aoAOIFVers:=AOIntfVersion;
addOn^.result:=VERSION;
end;
otherwise
{ do whatever you want done}
end;
Create a resource containing the add-on code. The resource type must be 'adOn', its ID must be set according to what message it should receive and its name is not important. All attributes of the resource should be clear. Store your resource in a file called 'PowerLock Add-Ons' together with any resources used by your add-on. You must also store within this file the 'adOn' resource ID 0 found within the 'Dispatcher Add-On' file.
The number of the resource should be determined from the following table:
aReq Message Resource ID
startup 100
timeOut 200
changeBtn 300
shutDownBtn 400
prefsBtn 500
okBtn 600
userListBtn 700
saveUserList 800
shutDown 900
quit 1000
pwIncorrect 1100
pwOK 1200
dlgItem 1300
bootBlocks 1900
unknown 9800 {any msgs sent from PowerLock that Dispatcher doesn't know}
version 9900
If you have multiple add-ons for the one message, you can determine which order they execute. For example, supposing you had four different add-ons that handle the aReqStartUp message. The one you want to execute first will have a resource ID of 100, the next one 101 and the last one 103. All four will execute PROVIDING none of them have set addOn^.continue to FALSE.
If you include a Method 1 add-on as resource 'adOn', ID#1, it will receive all messages after Dispatcher has handled them.
NOTE: Any resources used by your Add-On should only use Resource IDs starting from 200. All others are reserved for PowerLock.
Add-Ons: Using HyperCard XCMDs & XFCNs
The Dispatcher Add-On automatically calls any XCMDs or XFCNs you install using the same resource ID scheme as for the add-ons. ***IMPORTANT*** Any XCMD must NOT do any HyperCard callbacks - this, admittedly, renders the XCMD calling feature relatively useless as most XCMDs do callbacks. Future versions of PowerLock (and add-ons) may expand on HyperCard support.
Add-Ons: How to Determine the Best Method
If you are writing handlers for most of the messages sent by PowerLock, you are best off using the first method. If it worries you that you are restricting the ability for people to use Method 2 add-ons, why not include the necessary code to execute Method 2 addons within your add-on.
If your add-on serves a single message only, eg you are writing a BootBlocks Updater, then use Method 2. In this way, people can mix & match various add-ons as they wish. Don't worry about licensing implications - the Dispatcher Add-on can be freely distributed (although copyright, it is placed into the public domain).
IMPORTANT: Dispatcher has been designed so it will automatically call any adOn resource of with an ID of 1 after Dispatcher has had a chance to deal with the PowerLock event.
Add-Ons: The AddOn Record
plAOIFVers:integer;
contains the version of the Add-On interface currently in use by PowerLock. 200 = version 2.0.0. You are responsible for ensuring your add-on is running with a compatible PowerLock add-on interface - ignore version differences at your own risk.
aoAOIFVers:integer;
contains the version of the Add-On interface currently being used by the add-on.
plVersion: integer;
Version of PowerLock currently running: 200 = 2.0.0, 204=2.0.4 etc
username: str255;
returns the current username or NUL if none. Is also used by some callbacks.
attempts: integer;
returns the number of password attempts so far
userData: handle;
not used by PowerLock. Store a handle to your own data if required. Particularly useful for Method 2 add-ons to share data between calls.
bool: boolean;
returned by PowerLock when a true/false result is required. For instance, in the aReqBootBlocks message, bool contains the current status of the bootblocks button in the preferences dialog.
continue: boolean;
PowerLock sets this to true before calling your add-on. If you subsequently set this to false, the current operation is abandoned. For instance, if you receive the aReqPrefsBtn message and return false, even though the user clicked the Prefs button, the dialog won't be displayed.
misc: handle;
Currently not used by PowerLock. Intended to return a handle to internal PowerLock data. Do not rely on this handle. If you need a handle, use the UserData handle instead.
dlg:integer;
Currently only used by the aReqDlgItem message - returns the resource ID of the dialog which incurred the event. A number of constants for each of PowerLock's dialogs have been defined in the interface file for convenience.
item:integer;
Currently only used by the aReqDlgItem message - returns the dialog item number of the item incurring the particular event. The item could be a button, field, user item, picture, icon but must be flagged as "Enabled".
err: OSErr;
PowerLock sets to 'noErr' prior to calling your add-on. Returning an error in this field has no effect. Primarily useful for communication between method 2 addons.
request: str255;
Several callback routines take data from this field. If you are not using callbacks, you can make use of this field as you wish.
result: str255;
Several callback routines return data in this field. Again, can be used for other purposes if callbacks are not used.
fileRef: integer;
Contains the reference number of the PowerLock Add-Ons file. This file remains open whilst PowerLock is open. This field is also used by the ResFile callbacks - you must always reset it to the reference of the Add-On file with DoCBReq(cbReqAddOnResFile, addOnData). You can store any resources associated with your add-on in the add-on file. Within your add-On code use something like:
CurFile:=CurResFile;
UseResFile(addOn^.fileRef);
dlg:=GetNewDialog(dialogID,...,...)
... ...
UseResFile(CurFile);
callBackProc: procPtr;
Pointer to PowerLock's callback handling procedure. Change this at your own peril. May be useful to change if you want to intercept PowerLock's handling of certain callbacks. For example, a method 2 'startup' add-on may add a new message display routine for use by other add-ons. It need only trap the cbReqMsg message and send all other messages on to the PowerLock callback routine.
reserved1...reservedN
As the name implies, these fields are reserved. Please do not use them.
Add-Ons: Messages sent by PowerLock
PowerLock only attempts to send messages to add-ons if it finds a file named 'PowerLock Add-Ons' in the same folder as 'PowerLock Prefs' AND that file contains an 'adOn' resource ID 0. (You can also use a particular Add-On file by double-clicking or drop-launching). PowerLock is not concerned if your add-on doesn't handle a particular message sent by PowerLock provided your case statement includes an OTHERWISE clause.
aReqStartUp
Sent almost immediately after starting PowerLock. All fields of the AddOn record which are managed by PowerLock are initialised prior to this call. Prior to this message, the preferences file is opened. This message presents a good opportunity to initialise any user data.
aReqTimeOut
Sent just prior to displaying the timeout screen. Not sent at all if there is no screen file named 'PowerLock TimeOutScreen' available. Return false in continue to abort screen display.
Sent just after these buttons have been clicked. Return false in 'continue' and the button action will not proceed.
aReqSaveUserList
Sent just prior to saving the userlist. addOn^.username = the name of the super user. Return false in continue to not save the userlist.
aReqShutDown
Sent whenever PowerLock is about to call the Macintosh ShutDown routine. If continue remains true, the Macintosh will power down. If continue is false, PowerLock will remain active.
aReqQuit
Sent just prior to quitting PowerLock. Dispose of any temporary memory now. Note that 'continue=false' will not prevent PowerLock from quitting.
aReqPWIncorrect
Sent whenever an incorrect password is entered. Attempts contains the total number of password attempts. Username contains the current username or '' if none. Returning continue=false has no effect.
aReqPWOk
Sent once a valid password has been entered and validated. Setting continue to false rejects the password and prompts the user for the password again.
aReqDlgItem
Sent whenever an active dialog item (button, field, icon) is clicked. Look for the dialog ID in addOn^.dlg and the item number of the button/field etc in addOn^.item. Return false to ignore the dialog event. Note that the username and password fields (and some other components of PowerLock) do NOT use this mechanism.
aReqBootBlocks
Sent whenever someone clicks the 'BootBlocks Modification' option in the SuperSecurity Preferences dialog. addOn^.bool contains the current state (prior to clicking) of the button. So if addOn^.bool is false, you know that someone wants to make the boot blocks option active.
aReqVersion
Sent whenever PowerLock needs version information about your add-on. At present this message is only sent when someone clicks the PowerLock icon within the About dialog box. Set addOn^.result equal to your version string. All add-ons should set aoAOIFVers to the inbuilt function, AOIntfVersion, when they receive this message. If you don't want to display any version information, return continue:=false.
Add-Ons: CallBack Requests Available
You can access several internal PowerLock routines from your own add-ons. The syntax is 'DoCBReq(request, addOnData)'. You use constants for the request and you set & retrieve fields from the addOnData record. You can use the addOnData pointer you received when the add-on was called, or alternatively copy this to a new pointer - it may be necessary to do this in recursive callbacks. Remember to copy the original value in callBackProc.
cbReqLog
Logs 'request' to the log file providing the log file is enabled in the Preferences. Prefaces 'request' with the username, if any, and appends the time and date. eg if 'request' contains "SuperUser Changed" then the log file will include an entry similar to the following:
"Fred: SuperUser Changed at 4:37pm on Tue, 19 Nov, 1991"
cbReqLogRaw
Logs 'request' to the log file regardless of log file setting in preferences. Adds a carriage return to the end of the line but that is all.
cbReqMsg
Displays 'request' in the standard PowerLock message box.
cbReqAlert
Displays 'request' in the standard PowerLock alert box.
cbReqShutDown
Immediately shuts down PowerLock (but tidies up a bit first)
cbReqDraw
Makes use of the MacPaint/MacDraw routines in PowerLock. Send a PNTG or PICT file in 'request' (including full path info if necessary eg 'Hard Disk:Pics:PL Picture'). PowerLock will then create a new window (color if applicable), draw the file, wait for any keyboard or mouse event and then close the window.
cbReqYesNo
Puts up a Yes/No dialog box prompting with 'request'. 'result' will contain either "YES" or "NO".
cbReqUpdate
Force update of PowerLock's desktop (either a screen file or the desktop pattern). As PowerLock only utilises modal dialogs and doesn't really have a main event loop, you sometimes need to take care of desktop updating yourself - particularly if you draw dialogs about the place.
cbReqUsers
Returns in 'result' (in string form) the total number of user names set up. Use with cbReqUser to get all user names.
cbReqUser
Given a user ID (1 to 5) in 'request', returns the decrypted username in 'result' and also returns the current username in 'username'
cbReqUserID
Given a username in 'username', returns in 'result' the index into the five element user list for this username.
cbReqUsedToday
Returns true in bool if PowerLock has been used today.
cbReqAppResFile
Returns a file reference for the PowerLock application in 'fileRef'. You can then use this file in a UseResFile statement or similar. Once you have the fileRef, take a local copy and restore fileRef to what it was prior to your cbReqAppResFile call.
cbReqPrefsResFile
Returns a file reference for the PowerLock Prefs file in 'fileRef'. You can then use this file in a UseResFile statement or similar. Once you have the fileRef, take a local copy and restore fileRef to what it was prior to your cbReqPrefsResFile call.
cbReqAddOnResFile
Sets 'fileRef' to point to the Add-On file.
cbReqIsLicenced
Sets 'bool' to true if the version of PowerLock currently in use has been licenced. Sets bool to false if PowerLock is unlicenced (ie PostcardWare, as distributed). I may in future release add-ons that will only work with licenced copies of PowerLock. You are also free to write add-ons that will only operate with licenced PowerLocks although there is no benefit in you doing so other than encouraging people to register PowerLock and therefore encouraging me to continue to enhance it and develop further PostCardWare and ShareWare applications. Note that cbReqIsLicenced is not available until after PowerLock has started and therefore you cannot call it in response to an aReqStartUp event.
**NOTE RE RESFILE CALLBACKS**
You should always restore the current resource file to the way your add-on found it. Bracket ResFile callbacks as follows:
prevResFile:=CurResFile; {save current resource file}
DoCBReq(cbReqPrefsFile,addOn);
UseResFile(addOn^.fileRef);
{..do what you want to do...}
DoCBReq(cbReqAddOnResFile,addOn); {restore fileRef to point to Add-On}
UseResFile(prevResFile); {restore resource file to what it was}
Add-Ons: Distribution Arrangements
To distribute a PowerLock Add-On, do the following:
1. Set the creator of the file containing the resource to "PwrL" and its type to "adOn"
2. Include the Dispatcher resource as "adOn" ID 0 if it is required.
3. Name the file "<name> Add-On" where <name> is the name of your add-on
4. Include in your instructions details on how to use the Add-On e.g. rename it to "PowerLock Add-Ons", place it in the Preferences folder.
5. Also include details on how to use the add-on in an existing add-on file - eg. "copy these resources: DLOG ID#12, adOn #100,200,500,501, MENU #100"
6. You are free to use any of the supplied source code in your own add-ons and to distribute add-ons containing the supplied source code provided you send me a copy of your Add-On and any explanatory notes.